﻿
using Xacml.Core.Context;
using System;
using System.IO;
using System.Xml;

namespace Xacml.Core
{
  public sealed class ContextLoader
  {
    private ContextLoader()
    {
    }

    public static ContextDocumentReadWrite LoadContextDocument(string xmlDocument)
    {
      if (xmlDocument == null)
        throw new ArgumentNullException("xmlDocument");
      XacmlVersion xacmlVersion = ContextLoader.GetXacmlVersion((TextReader) new StreamReader(xmlDocument));
      return ContextLoader.LoadContextDocument((XmlReader) new XmlTextReader((TextReader) new StringReader(xmlDocument)), xacmlVersion);
    }

    public static ContextDocumentReadWrite LoadContextDocument(Stream xmlDocument)
    {
      if (xmlDocument == null)
        throw new ArgumentNullException("xmlDocument");
      XacmlVersion xacmlVersion = ContextLoader.GetXacmlVersion((TextReader) new StreamReader(xmlDocument));
      xmlDocument.Position = 0L;
      return ContextLoader.LoadContextDocument((XmlReader) new XmlTextReader((TextReader) new StreamReader(xmlDocument)), xacmlVersion);
    }

    public static ContextDocumentReadWrite LoadContextDocument(string xmlDocument, XacmlVersion schemaVersion)
    {
      if (xmlDocument == null)
        throw new ArgumentNullException("xmlDocument");
      return ContextLoader.LoadContextDocument((XmlReader) new XmlTextReader((TextReader) new StringReader(xmlDocument)), schemaVersion);
    }

    public static ContextDocumentReadWrite LoadContextDocument(Stream xmlDocument, XacmlVersion schemaVersion)
    {
      if (xmlDocument == null)
        throw new ArgumentNullException("xmlDocument");
      return ContextLoader.LoadContextDocument((XmlReader) new XmlTextReader((TextReader) new StreamReader(xmlDocument)), schemaVersion);
    }

    public static ContextDocumentReadWrite LoadContextDocument(XmlReader reader, XacmlVersion schemaVersion)
    {
      if (reader == null)
        throw new ArgumentNullException("reader");
      return (ContextDocumentReadWrite) new ContextDocument(reader, schemaVersion);
    }

    public static ContextDocumentReadWrite LoadContextDocument(string xmlDocument, DocumentAccess access)
    {
      if (xmlDocument == null)
        throw new ArgumentNullException("xmlDocument");
      XacmlVersion xacmlVersion = ContextLoader.GetXacmlVersion((TextReader) new StreamReader(xmlDocument));
      return ContextLoader.LoadContextDocument((XmlReader) new XmlTextReader((TextReader) new StringReader(xmlDocument)), xacmlVersion, access);
    }

    public static ContextDocumentReadWrite LoadContextDocument(Stream xmlDocument, DocumentAccess access)
    {
      if (xmlDocument == null)
        throw new ArgumentNullException("xmlDocument");
      XacmlVersion xacmlVersion = ContextLoader.GetXacmlVersion((TextReader) new StreamReader(xmlDocument));
      xmlDocument.Position = 0L;
      return ContextLoader.LoadContextDocument((XmlReader) new XmlTextReader((TextReader) new StreamReader(xmlDocument)), xacmlVersion, access);
    }

    public static ContextDocumentReadWrite LoadContextDocument(string xmlDocument, XacmlVersion schemaVersion, DocumentAccess access)
    {
      if (xmlDocument == null)
        throw new ArgumentNullException("xmlDocument");
      return ContextLoader.LoadContextDocument((XmlReader) new XmlTextReader((TextReader) new StringReader(xmlDocument)), schemaVersion, access);
    }

    public static ContextDocumentReadWrite LoadContextDocument(Stream xmlDocument, XacmlVersion schemaVersion, DocumentAccess access)
    {
      if (xmlDocument == null)
        throw new ArgumentNullException("xmlDocument");
      return ContextLoader.LoadContextDocument((XmlReader) new XmlTextReader((TextReader) new StreamReader(xmlDocument)), schemaVersion, access);
    }

    public static ContextDocumentReadWrite LoadContextDocument(XmlReader reader, XacmlVersion schemaVersion, DocumentAccess access)
    {
      if (reader == null)
        throw new ArgumentNullException("reader");
      if (access == DocumentAccess.ReadOnly)
        return (ContextDocumentReadWrite) new ContextDocument(reader, schemaVersion);
      if (access == DocumentAccess.ReadWrite)
        return new ContextDocumentReadWrite(reader, schemaVersion);
      return (ContextDocumentReadWrite) null;
    }

    private static XacmlVersion GetXacmlVersion(TextReader textReader)
    {
      XmlTextReader xmlTextReader = new XmlTextReader(textReader);
      while (xmlTextReader.Read())
      {
        if (xmlTextReader.LocalName == "Request" || xmlTextReader.LocalName == "Response")
        {
          if (xmlTextReader.NamespaceURI == "urn:oasis:names:tc:xacml:1.0:context")
            return XacmlVersion.Version11;
          if (xmlTextReader.NamespaceURI == "urn:oasis:names:tc:xacml:2.0:context")
            return XacmlVersion.Version20;
        }
      }
      throw new Exception(Resource.ResourceManager[Resource.MessageKey.exc_invalid_document_format_no_policyorpolicyset]);
    }
  }
}
